# -*- coding: utf-8 -*-
"""Memcached cache backend

Currently works only with python-memcached.

settings.CACHE_BACKEND = 'yamb.backend://127.0.0.1:11212;127.0.0.1:11211/'

settings.CACHE_PICKLE_PROTOCOL # 0,1,2
settings.CACHE_MIN_COMPRESSION_LEN

To select node for key use 2-element tuple: (node_number, key)
eg.: (1, 'com.example.key_on_node_1')
"""

import logging
import pickle
import zlib
from django.conf import settings
from django.core.cache.backends.base import InvalidCacheBackendError
from django.core.cache.backends.memcached import CacheClass as MemcCacheClass
from django.utils.encoding import smart_str as _smart_str
from django.utils.encoding import smart_unicode

log = logging.getLogger(__name__)

try:
    import memcache
except:
    raise InvalidCacheBackendError("Memcached cache backend requires either the 'memcache' library")

def yamb_smart_str(s):
    if isinstance(s, tuple):
        serverhash, key = s
        key = _smart_str(key)
        return (serverhash, key)
    else:
        return _smart_str(s)


class CacheClass(MemcCacheClass):
    def __init__(self, server, params):
        MemcCacheClass.__init__(self, server, params)
        self._cache = memcache.Client(server.split(';'), \
                                      pickleProtocol=getattr(settings, 'CACHE_PICKLE_PROTOCOL', 0))

    def _server_hash(self, key):
        if isinstance(key, tuple):
            srv, k = key
        else:
            srv, k = '-', key
        return srv, k

    def _pickled_size(self, value):
        pickled_size = 0
        if settings.DEBUG or (log.getEffectiveLevel() <= logging.DEBUG):
            pickled = pickle.dumps(value, getattr(settings, 'CACHE_PICKLE_PROTOCOL', 0))
            pickled_size = len(pickled)
            if getattr(settings, 'CACHE_MIN_COMPRESSION_LEN', 0) >= pickled_size:
                pickled = zlib.compress(pickled)
                pickled_size = len(pickled)
                del pickled
        return pickled_size

    def add(self, key, value, timeout=0):
        if isinstance(value, unicode):
            value = value.encode('utf-8')
        return self._cache.add(yamb_smart_str(key), value, timeout or self.default_timeout)

    def get(self, key, default=None):
        value = self._cache.get(yamb_smart_str(key))
        srv, k = self._server_hash(key)
        pickled_size = self._pickled_size(value)

        if value is None:
            log.debug("MISS %s %s %s", k, srv, pickled_size)
        else:
            log.debug("HIT %s %s %s", k, srv, pickled_size)

        if value is None:
            return default
        else:
            if isinstance(value, basestring):
                return smart_unicode(value)
            else:
                return value

    def set(self, key, value, timeout=0):
        print "tyeaa"
        if isinstance(value, unicode):
            value = value.encode('utf-8')

        srv, k = self._server_hash(key)
        pickled_size = self._pickled_size(value)
        log.debug("SET %s %s %s", k, srv, pickled_size)
        self._cache.set(yamb_smart_str(key), value, timeout or self.default_timeout, \
                        getattr(settings, 'CACHE_MIN_COMPRESSION_LEN', 0))

    def delete(self, key):
        srv, k = self._server_hash(key)
        log.debug("DELETE %s %s -", k, srv)
        self._cache.delete(yamb_smart_str(key))

    def get_many(self, keys):
        return self._cache.get_multi(map(yamb_smart_str, keys))

    def incr(self, key, delta=1):
        srv, k = self._server_hash(key)
        log.debug("INCR %s %s -", k, srv)
        return self._cache.incr(key, delta)

    def decr(self, key, delta=1):
        srv, k = self._server_hash(key)
        log.debug("DECR %s %s -", k, srv)
        return self._cache.decr(key, delta)

